﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compilex.Automata
{
    public class Token
    {
        public string Name { get; set; }
        public string Lexeme { get; set; }
        public Token(string name)
        {
            this.Name = name;
            this.Lexeme = name;
        }

        public Token(string name, string lexeme)
        {
            this.Name = name;
            this.Lexeme = lexeme;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj))
                return true;

            if (obj is Token)
            {
                return ((Token)obj).Name == this.Name;
            }
            else
            {
                return false;
            }
        }

        public override int GetHashCode()
        {
            return this.Name.GetHashCode();
        }
        public override string ToString()
        {
            if(Lexeme == null)
                return String.Format("<{0}>", this.Name);
            else
                return String.Format("<{0}, {1}1>", this.Lexeme);
        }
    }

    public class OperatorToken : Token
    {
        public OperatorToken(string tokenName)
            : base(tokenName)
        {
        }
    }

    public class AttributeToken<T> : Token
    {
        public T Attribute { get; set; }
        public AttributeToken(string tag, T attribute)
            : base(tag, attribute.ToString())
        {
            this.Attribute = attribute;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj))
                return true;

            if (obj is AttributeToken<T>)
            {
                return ((AttributeToken<T>)obj).Name == this.Name
                    && ((AttributeToken<T>)obj).Attribute.Equals(this.Attribute);
            }
            else
            {
                return false;
            }
        }

        public override int GetHashCode()
        {
            return this.Name.GetHashCode() + this.Attribute.GetHashCode();
        }

        public override string ToString()
        {
            return String.Format("<{0}, {1}>", this.Name, this.Attribute.ToString());
        }
    }
    public class WordToken : AttributeToken<string>
    {
        public WordToken(string tokenName, string value)
            : base(tokenName, value)
        {
        }
    }

    public class CaracterToken : AttributeToken<string>
    {
        public const string TokenName = "CAR";
        public CaracterToken(string value)
            : base(TokenName, value)
        {
        }
    }

    public class KeywordToken : WordToken
    {
        public KeywordToken(string tokenName)
            : base(tokenName, tokenName)
        {
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj))
                return true;

            if (obj is Token)
            {
                return ((Token)obj).Name == this.Name;
            }
            else
            {
                return false;
            }
        }

        public override int GetHashCode()
        {
            return this.Name.GetHashCode();
        }

        public override string ToString()
        {
            return String.Format("<{0}>", this.Name);
        }
    }

    public class IdentifierToken : WordToken
    {
        public const string TokenName = "ID";
        public IdentifierToken(string identifierName)
            : base(TokenName, identifierName)
        {
        }
    }


    public class LiteralToken : WordToken
    {
        public const string TokenName = "LIT";
        public LiteralToken(string literal)
            : base(TokenName, literal)
        {
        }
    }


    public class IntToken : AttributeToken<int>
    {
        public const string TokenName = "INT";
        public IntToken(int value)
            : base(TokenName, value)
        {
        }
    }
    public class FloatToken : AttributeToken<float>
    {
        public const string TokenName = "FLOAT";
        public FloatToken(float value)
            : base(TokenName, value)
        {
        }
    }
}
